{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<table style=\"float:left; border:none\">\n",
    "   <tr style=\"border:none\">\n",
    "       <td style=\"border:none\">\n",
    "           <a href=\"http://bokeh.pydata.org/\">     \n",
    "           <img \n",
    "               src=\"http://bokeh.pydata.org/en/latest/_static/bokeh-transparent.png\" \n",
    "               style=\"width:70px\"\n",
    "           >\n",
    "           </a>    \n",
    "       </td>\n",
    "       <td style=\"border:none\">\n",
    "           <h1>Bokeh Tutorial &mdash; <tt style=\"display:inline\">bokeh.models</tt> interface</h1>\n",
    "       </td>\n",
    "   </tr>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## Models\n",
    "\n",
    "NYTimes interactive chart [Usain Bolt vs. 116 years of Olympic sprinters](http://www.nytimes.com/interactive/2012/08/05/sports/olympics/the-100-meter-dash-one-race-every-medalist-ever.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first thing we need is to get the data. The data for this chart is located in the ``bokeh.sampledata`` module as a Pandas DataFrame. You can see the first ten rows below:?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from bokeh.sampledata.sprint import sprint\n",
    "sprint[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we import some of the Bokeh models that need to be assembled to make a plot. At a minimum, we need to start with ``Plot``, the glyphs (``Circle`` and ``Text``) we want to display, as well as ``ColumnDataSource`` to hold the data and range obejcts to set the plot bounds. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from bokeh.io import output_notebook, show\n",
    "from bokeh.models.glyphs import Circle, Text\n",
    "from bokeh.models import ColumnDataSource, Range1d, DataRange1d, Plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "output_notebook()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setting up Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "abbrev_to_country = {\n",
    "    \"USA\": \"United States\",\n",
    "    \"GBR\": \"Britain\",\n",
    "    \"JAM\": \"Jamaica\",\n",
    "    \"CAN\": \"Canada\",\n",
    "    \"TRI\": \"Trinidad and Tobago\",\n",
    "    \"AUS\": \"Australia\",\n",
    "    \"GER\": \"Germany\",\n",
    "    \"CUB\": \"Cuba\",\n",
    "    \"NAM\": \"Namibia\",\n",
    "    \"URS\": \"Soviet Union\",\n",
    "    \"BAR\": \"Barbados\",\n",
    "    \"BUL\": \"Bulgaria\",\n",
    "    \"HUN\": \"Hungary\",\n",
    "    \"NED\": \"Netherlands\",\n",
    "    \"NZL\": \"New Zealand\",\n",
    "    \"PAN\": \"Panama\",\n",
    "    \"POR\": \"Portugal\",\n",
    "    \"RSA\": \"South Africa\",\n",
    "    \"EUA\": \"United Team of Germany\",\n",
    "}\n",
    "\n",
    "gold_fill   = \"#efcf6d\"\n",
    "gold_line   = \"#c8a850\"\n",
    "silver_fill = \"#cccccc\"\n",
    "silver_line = \"#b0b0b1\"\n",
    "bronze_fill = \"#c59e8a\"\n",
    "bronze_line = \"#98715d\"\n",
    "\n",
    "fill_color = { \"gold\": gold_fill, \"silver\": silver_fill, \"bronze\": bronze_fill }\n",
    "line_color = { \"gold\": gold_line, \"silver\": silver_line, \"bronze\": bronze_line }\n",
    "\n",
    "def selected_name(name, medal, year):\n",
    "    return name if medal == \"gold\" and year in [1988, 1968, 1936, 1896] else None\n",
    "\n",
    "t0 = sprint.Time[0]\n",
    "\n",
    "sprint[\"Abbrev\"]       = sprint.Country\n",
    "sprint[\"Country\"]      = sprint.Abbrev.map(lambda abbr: abbrev_to_country[abbr])\n",
    "sprint[\"Medal\"]        = sprint.Medal.map(lambda medal: medal.lower())\n",
    "sprint[\"Speed\"]        = 100.0/sprint.Time\n",
    "sprint[\"MetersBack\"]   = 100.0*(1.0 - t0/sprint.Time)\n",
    "sprint[\"MedalFill\"]    = sprint.Medal.map(lambda medal: fill_color[medal])\n",
    "sprint[\"MedalLine\"]    = sprint.Medal.map(lambda medal: line_color[medal])\n",
    "sprint[\"SelectedName\"] = sprint[[\"Name\", \"Medal\", \"Year\"]].apply(tuple, axis=1).map(lambda args: selected_name(*args))\n",
    "\n",
    "source = ColumnDataSource(sprint)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Plot with Glyphs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "plot_options = dict(plot_width=800, plot_height=480, toolbar_location=None, \n",
    "                    outline_line_color=None, title = \"Usain Bolt vs. 116 years of Olympic sprinters\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "radius = dict(value=5, units=\"screen\")\n",
    "medal_glyph = Circle(x=\"MetersBack\", y=\"Year\", radius=radius, fill_color=\"MedalFill\", \n",
    "                     line_color=\"MedalLine\", fill_alpha=0.5)\n",
    "\n",
    "athlete_glyph = Text(x=\"MetersBack\", y=\"Year\", x_offset=10, text=\"SelectedName\",\n",
    "    text_align=\"left\", text_baseline=\"middle\", text_font_size=\"9pt\")\n",
    "\n",
    "no_olympics_glyph = Text(x=7.5, y=1942, text=[\"No Olympics in 1940 or 1944\"],\n",
    "    text_align=\"center\", text_baseline=\"middle\",\n",
    "    text_font_size=\"9pt\", text_font_style=\"italic\", text_color=\"silver\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xdr = Range1d(start=sprint.MetersBack.max()+2, end=0)  # +2 is for padding\n",
    "ydr = DataRange1d(range_padding=0.05)  \n",
    "\n",
    "plot = Plot(x_range=xdr, y_range=ydr, **plot_options)\n",
    "plot.add_glyph(source, medal_glyph)\n",
    "plot.add_glyph(source, athlete_glyph)\n",
    "plot.add_glyph(no_olympics_glyph)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "show(plot)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding Axes and Grids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from bokeh.models import Grid, LinearAxis, SingleIntervalTicker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xdr = Range1d(start=sprint.MetersBack.max()+2, end=0)  # +2 is for padding\n",
    "ydr = DataRange1d(range_padding=0.05)  \n",
    "\n",
    "plot = Plot(x_range=xdr, y_range=ydr, **plot_options)\n",
    "plot.add_glyph(source, medal_glyph)\n",
    "plot.add_glyph(source, athlete_glyph)\n",
    "plot.add_glyph(no_olympics_glyph)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xticker = SingleIntervalTicker(interval=5, num_minor_ticks=0)\n",
    "xaxis = LinearAxis(ticker=xticker, axis_line_color=None, major_tick_line_color=None,\n",
    "                   axis_label=\"Meters behind 2012 Bolt\", axis_label_text_font_size=\"10pt\", \n",
    "                   axis_label_text_font_style=\"bold\")\n",
    "plot.add_layout(xaxis, \"below\")\n",
    "\n",
    "xgrid = Grid(dimension=0, ticker=xaxis.ticker, grid_line_dash=\"dashed\")\n",
    "plot.add_layout(xgrid)\n",
    "\n",
    "yticker = SingleIntervalTicker(interval=12, num_minor_ticks=0)\n",
    "yaxis = LinearAxis(ticker=yticker, major_tick_in=-5, major_tick_out=10)\n",
    "plot.add_layout(yaxis, \"right\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "show(plot)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding a Hover Tool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from bokeh.models import HoverTool"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "tooltips = \"\"\"\n",
    "<div>\n",
    "    <span style=\"font-size: 15px;\">@Name</span>&nbsp;\n",
    "    <span style=\"font-size: 10px; color: #666;\">(@Abbrev)</span>\n",
    "</div>\n",
    "<div>\n",
    "    <span style=\"font-size: 17px; font-weight: bold;\">@Time{0.00}</span>&nbsp;\n",
    "    <span style=\"font-size: 10px; color: #666;\">@Year</span>\n",
    "</div>\n",
    "<div style=\"font-size: 11px; color: #666;\">@{MetersBack}{0.00} meters behind</div>\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "xdr = Range1d(start=sprint.MetersBack.max()+2, end=0)  # +2 is for padding\n",
    "ydr = DataRange1d(range_padding=0.05)  \n",
    "\n",
    "plot = Plot(x_range=xdr, y_range=ydr, **plot_options)\n",
    "medal = plot.add_glyph(source, medal_glyph)  # we need this renderer to configure the hover tool\n",
    "plot.add_glyph(source, athlete_glyph)\n",
    "plot.add_glyph(no_olympics_glyph)\n",
    "\n",
    "xticker = SingleIntervalTicker(interval=5, num_minor_ticks=0)\n",
    "xaxis = LinearAxis(ticker=xticker, axis_line_color=None, major_tick_line_color=None,\n",
    "                   axis_label=\"Meters behind 2012 Bolt\", axis_label_text_font_size=\"10pt\", \n",
    "                   axis_label_text_font_style=\"bold\")\n",
    "plot.add_layout(xaxis, \"below\")\n",
    "\n",
    "xgrid = Grid(dimension=0, ticker=xaxis.ticker, grid_line_dash=\"dashed\")\n",
    "plot.add_layout(xgrid)\n",
    "\n",
    "yticker = SingleIntervalTicker(interval=12, num_minor_ticks=0)\n",
    "yaxis = LinearAxis(ticker=yticker, major_tick_in=-5, major_tick_out=10)\n",
    "plot.add_layout(yaxis, \"right\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "hover = HoverTool(tooltips=tooltips, renderers=[medal])\n",
    "plot.add_tools(hover)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "show(plot)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from bubble_plot import get_1964_data\n",
    "\n",
    "def get_plot():\n",
    "    return Plot(\n",
    "        x_range=Range1d(1, 9), y_range=Range1d(20, 100),\n",
    "        title=\"\", plot_width=800, plot_height=400,\n",
    "        outline_line_color=None, toolbar_location=None,\n",
    "    )\n",
    "\n",
    "df = get_1964_data()\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# EXERCISE: Add Circles to the plot from the data in `df`. \n",
    "# With `fertility` for the x coordinates, `life` for the y coordinates.\n",
    "\n",
    "plot = get_plot()\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# EXERCISE: Color the circles by region_color & change the size of the color by population\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# EXERCISE: Add axes and grid lines\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# EXERCISE: Manually add a legend using Circle & Text. The color key is as follows \n",
    "\n",
    "region_name_and_color = [\n",
    "    ('America', '#3288bd'),\n",
    "    ('East Asia & Pacific', '#99d594'),\n",
    "    ('Europe & Central Asia', '#e6f598'),\n",
    "    ('Middle East & North Africa', '#fee08b'),\n",
    "    ('South Asia', '#fc8d59'),\n",
    "    ('Sub-Saharan Africa', '#d53e4f')\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
